package it.uniroma3.gaia.sama.schemaExchangeGenerator;

import java.util.*;

public class CombinationGenerator<T extends Object> {


	public CombinationGenerator() {

	}
	
	/**
	 * return all the combination of all size of the elements of the Combination<T>
	 * @param toGroup
	 * @return
	 */
	public List<Combination<T>> getCombiations(Collection<T> toGroup){
		List<Combination<T>> result = new LinkedList<Combination<T>>();
		for(T s : toGroup){
			Combination<T> group = new Combination<T>();
			group.add(s);
			result.add(group);
		}
		for(int i = 1; i<= toGroup.size();i++){
			List<Combination<T>> h = this.getSelectedSizeLists(i, result);
			for(T s : toGroup){
				List<Combination<T>> nc = this.getNotContaining(s,h);
				List<Combination<T>> partialResult = combineElement(s, nc);
				for(Combination<T> p: partialResult){
					if(!contains(result,p))
						result.add(p);
				}
			}
		}

		return result;
	}
	/**
	 * Verify that a List<Combination<T>> contains a Combination<T> ignoring order of the elements.
	 * @param container
	 * @param toVerify
	 * @return
	 */
	private boolean contains(List<Combination<T>> container, Combination<T> toVerify){
		for(Combination<T> a : container){
			if(a.equals(toVerify))
				return true;
		}
		return false;
	}
	/**
	 * Combine add element s to every Combination<T> of List<Combination<T>>
	 * @param s
	 * @param toCombine
	 * @return List<Combination<T>>
	 */
	private List<Combination<T>> combineElement(T s , List<Combination<T>> toCombine){
		List<Combination<T>> result = new LinkedList<Combination<T>>();
		for(Combination<T> l : toCombine){
			Combination<T> k = new Combination<T>();
			k.add(s);
			k.addAll(l);
			result.add(k);
		}
		return result;
	}
	
	/**
	 * return a List<Combination<T>> that not contains element
	 * @param element
	 * @param list
	 * @return a List<Combination<T>> that not contains elment
	 */
	private List<Combination<T>> getNotContaining(T element,List<Combination<T>> list){
		List<Combination<T>> result = new LinkedList<Combination<T>>();
		for(Combination<T> l : list){
			if(!l.contains(element))
				result.add(l);
		}
		return result;
	}
	/**
	 * return all the lists of the selected size from List<Combination<T>>
	 * @param size
	 * @param list
	 * @return all the lists of the selected size from List<Combination<T>>
	 */
	private List<Combination<T>> getSelectedSizeLists(int size, List<Combination<T>> list){
		List<Combination<T>> result = new LinkedList<Combination<T>>();
		for(Combination<T> l : list){
			if(l.size() == size)
				result.add(l);
		}
		
		return result;
	}
}
